package com.lew.jlight.redis;

import com.google.common.base.Preconditions;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.util.Pool;


public class JedisLite {

    private JedisTemplate template;
    private Pool<Jedis> pool;
    private GenericObjectPoolConfig config;


    public JedisLite(Pool<Jedis> pool) {
        template = new JedisTemplate(pool);
    }

    /**
     * redis 主从sentinel模式
     *
     * @param masterName        主机名称
     * @param sentinelAddresses 连接地址 127.0.0.1:26379,127.0.0.2:26379
     */
    public JedisLite(String masterName, String sentinelAddresses) {
        buildConfig();
        initSentinel(masterName, build(sentinelAddresses));
    }

    /**
     * redis 主从sentinel模式
     *
     * @param masterName        主机名称
     * @param sentinelAddresses 连接地址 127.0.0.1:26379,127.0.0.2:26379
     * @param config            连接池配置信息
     */
    public JedisLite(String masterName, String sentinelAddresses, GenericObjectPoolConfig config) {
        Preconditions.checkNotNull(config);
        this.config = config;
        initSentinel(masterName, build(sentinelAddresses));
    }

    private void initSentinel(String masterName, Set<String> set) {
        this.pool = new JedisSentinelPool(masterName, set, config);
        this.template = new JedisTemplate(pool);
    }

    /**
     * 直连redis
     *
     * @param host host 主机地址
     * @param port port 主机端口
     */
    public JedisLite(String host, int port) {
        buildConfig();
        initJedis(host, port);
    }

    public JedisLite(String host, int port, GenericObjectPoolConfig config) {
        this.config = config;
        initJedis(host, port);
    }

    private void initJedis(String host, int port) {
        Pool<Jedis> pool = new JedisPool(config, host, port);
        template = new JedisTemplate(pool);
    }

    /**
     * 关闭pool
     */
    public void destroy() {
        if (pool != null) {
            pool.destroy();
        }
    }

    public JedisTemplate getTemplate() {
        return this.template;
    }

    public void setInt(String key, int value) {
        template.set(key, String.valueOf(value));
    }

    public void setInt(String key, int value, int expire) {
        template.setex(key, String.valueOf(value), expire);
    }

    public Integer getInt(String key) {
        return template.getAsInt(key);
    }

    public void increaseInt(String key) {
        template.incr(key);
    }

    public Integer decreaseInt(String key) {
        return Integer.valueOf(String.valueOf(template.decr(key)));
    }


    public void setLong(String key, long value) {
        template.set(key, String.valueOf(value));
    }

    public void setLong(String key, long value, int expire) {
        template.setex(key, String.valueOf(value), expire);
    }

    public Long getLong(String key) {
        return template.getAsLong(key);
    }

    public Long increaseLong(String key) {
        return template.incr(key);
    }

    public Long decreaseLong(String key) {
        return template.decr(key);
    }


    public void setString(String key, String value) {
        template.set(key, value);
    }

    public void setString(String key, String value, int expire) {
        template.setex(key, value, expire);
    }

    public String getString(String key) {
        return template.get(key);
    }

    public void setMap(String key, String field, String value) {
        template.hset(key, field, value);
    }

    public void setMap(String key, String field, String value, int expiredSecond) {
        template.hset(key, field, value);
        template.expire(key, expiredSecond);
    }

    public String getMap(String key, String field) {
        return template.hget(key, field);
    }

    public void removeMap(String key, String... field) {
        template.hdel(key, field);
    }

    public boolean exisitsMap(String key, String field) {
        return template.hexists(key, field);
    }

    public byte[] getByteArray(String key) {
        return template.get(key.getBytes(StandardCharsets.UTF_8));
    }

    public void setByteArray(String key, byte[] bytes) {
        template.set(key.getBytes(StandardCharsets.UTF_8), bytes);
    }

    public void setByteArray(String key, byte[] bytes, int expire) {
        template.setex(key.getBytes(StandardCharsets.UTF_8), bytes, expire);
    }

    public boolean getBoolean(String key) {
        return template.get(key).equals("0");
    }

    public void setBoolean(String key, boolean value) {
        template.set(key, value ? "1" : "0");
    }

    public void setSet(String key, String value) {
        template.sadd(key, value);
    }

    public Set<String> setSmembers(String key) {
        return template.smembers(key);
    }

    public Map<String, String> getAllMap(String key) {
        return template.hgetAll(key);
    }

    public Boolean deleteByKey(String key) {
        return template.del(key);
    }

    public boolean exists(String key) {
        return template.exists(key);
    }

    private void buildConfig() {
        config = new GenericObjectPoolConfig();
        config.setMaxTotal(100);
        config.setMaxIdle(20);
        config.setMinIdle(5);
        config.setMinEvictableIdleTimeMillis(20 * 1000);
        config.setMaxWaitMillis(5 * 1000);
        config.setTestWhileIdle(true);
        config.setTimeBetweenEvictionRunsMillis(10 * 1000);
    }

     private Set<String> build(String sentinelAddresses) {
        String[] addresses = sentinelAddresses.split(",");
        Set<String> set = new HashSet<>();
        Collections.addAll(set, addresses);
        return set;
    }
}
